/**
 * 根据组件code生成json配置
 * 
 * 组件结构示例
 *  import React, { useState, useEffect, memo } from "react";
    export default memo((props) => {
    return (
        <Page className={styles["page"]}>
        <Nav className={styles["nav"]}></Nav>
        <i></i>
        <Button
            onClick={() => {
            let a = "22";
            console.log("打印一下");
            }}
        ></Button>
        <FormSubmit></FormSubmit>
        </Page>
    );
    });
 */


import _generate from "@babel/generator";
const generate = _generate.default;
import { parse } from "@babel/parser";
import _template from "@babel/template";
const template = _template.default;
import _traverse from "@babel/traverse";
const traverse = _traverse.default;
import * as t from "@babel/types";
import fs from 'fs';
import path from 'path';
import prettier from "prettier";
import serialize from 'serialize-javascript';

export default class CodeAstJson {
    constructor({
        entryPath,
        outputPath,
        projectConfig,
        finishedCallback,
    } = props) {
        this.projectConfig = projectConfig;
        this.json = [];
        // 获取jsx文件内容
        const jsx = fs.readFileSync(entryPath, { encoding: 'utf8', sourceType: "module" });
        // jsx解析成ast
        const jsxAst = parse(jsx, { sourceType: "module", plugins: ["jsx"] });
        // todo: 打印ast
        // console.log('jsxAst', jsxAst)
        // fs.writeFileSync('./test.ast.json', serialize(jsxAst));
        // 获取默认导出函数体块级作用域内容ast
        let bodyAst = '';
        traverse(jsxAst, {
            enter(path) {
                if (path.isExportDefaultDeclaration()) {
                    bodyAst = path.node.declaration.arguments[0].body.body
                    path.stop();
                }
            },
        });
        // 找到默认导出函数体块级作用域内容return节点ast
        const returnAst = bodyAst.find(item => item.type === 'ReturnStatement');
        // 处理return节点ast，得到页面的json数据结构
        const reduceAst = (ast, arr) => {
            if (Array.isArray(ast)) {
                ast.forEach(item => {
                    if (item.type === 'JSXElement') {
                        let ele = {props: {}};
                        ele.componentName = item.openingElement.name.name;
                        item.openingElement?.attributes && 
                        item.openingElement.attributes.map(attr => {
                            const [key, value] =  this.parseProps(attr);
                            
                            if (value !== undefined && value !== null && value !== '') {
                                ele.props[key] = value;
                            }
                        })
                        
                        arr.push(ele);
                        if (Array.isArray(item.children) && item.children.length > 0) {
                            ele.children = [];
                            reduceAst(item.children, ele.children);
                        }
                    }
                })
            }
        }
        reduceAst([returnAst.argument], this.json)
        // 序列化json（json中包含函数体等）
        this.json = serialize(this.json[0])
        // 格式化json
        this.json = prettier.format(this.json);
        // 输出json
        fs.writeFileSync(outputPath, `export default ${this.json}`);
        // 执行成功回调
        typeof finishedCallback === 'function' && finishedCallback();
    }

    parseProps = (attrAst) => {
        console.log(attrAst)
        if (attrAst.type !== 'JSXAttribute') return;
        const { styleImportType } = this.projectConfig;
        let key = null;
        let value = null;
        // 获取属性key
        if (attrAst.name.type === 'JSXIdentifier') {
            key = attrAst.name.name;
        }
        // 获取属性值, 若属性为{}表达式
        if (attrAst.value.type === 'JSXExpressionContainer') {
            const expressionAst = attrAst.value.expression;
            // className单独处理
            if (key === 'className') {
                if (styleImportType === 'css_module') {
                    value = attrAst.value.expression?.property?.value;
                }
            // props属性值是函数处理
            } else if (attrAst.value.expression.type === 'ArrowFunctionExpression') {
                const expression = generate(expressionAst).code;
                value = eval(expression);
            // props属性值为字符串
            } else if (attrAst.value.expression.type === 'StringLiteral') {
                value = attrAst.value.expression.value;
            }
        // 获取属性值, 若属性为字符串
        } else if (attrAst.value.type === 'StringLiteral') {
            value = attrAst.value.value;
        }

        return [key, value]
    }
}
